package me.dustin.jex.feature.command.impl;

import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.mojang.brigadier.arguments.IntegerArgumentType;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.tree.CommandNode;
import me.dustin.jex.JexClient;
import me.dustin.jex.feature.command.core.Command;
import me.dustin.jex.feature.command.core.annotate.Cmd;
import me.dustin.jex.feature.command.core.arguments.BlockStateArgumentType;
import me.dustin.jex.feature.command.core.arguments.MessageArgumentType;
import me.dustin.jex.feature.command.core.arguments.PlayerNameArgumentType;
import me.dustin.jex.feature.command.core.arguments.Vec3ArgumentType;
import me.dustin.jex.helper.misc.ChatHelper;
import me.dustin.jex.helper.misc.Wrapper;
import me.dustin.jex.helper.network.NetworkHelper;
import me.dustin.jex.helper.player.InventoryHelper;
import net.fabricmc.fabric.api.client.command.v1.FabricClientCommandSource;
import net.minecraft.block.BlockState;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.nbt.*;
import net.minecraft.nbt.visitor.NbtTextFormatter;
import net.minecraft.network.packet.c2s.play.CreativeInventoryActionC2SPacket;
import net.minecraft.text.*;
import net.minecraft.util.Formatting;
import net.minecraft.util.math.Vec3d;

import java.util.Random;

@Cmd(name = "itemexploit", description = "Perform various item exploits. Must be in creative", alias = "items")
public class CommandItemExploit extends Command {
    @Override
    public void registerCommand() {
        CommandNode<FabricClientCommandSource> node = dispatcher.register(literal(this.name).then(literal("fireball").then(argument("power", IntegerArgumentType.integer(1)).executes(context -> {
            int power = IntegerArgumentType.getInteger(context, "power");
            ItemStack stack = new ItemStack(Items.CREEPER_SPAWN_EGG);
            stack.setCustomName(new LiteralText("§bBig Boom"));
            NbtCompound compound = stack.getOrCreateSubTag("EntityTag");
            compound.putString("id", "minecraft:fireball");
            compound.putDouble("ExplosionPower", power);
            givePlayerStack(context, stack);
            return 1;
        }))).then(literal("slime").then(argument("size", IntegerArgumentType.integer(0)).executes(context -> {
            int size = IntegerArgumentType.getInteger(context, "size");
            ItemStack stack = new ItemStack(Items.SLIME_SPAWN_EGG);
            stack.setCustomName(new LiteralText("§7Slime size §b" + size));
            NbtCompound compound = stack.getOrCreateSubTag("EntityTag");
            compound.putBoolean("PersistenceRequired", true);
            compound.putString("id", "minecraft:slime");
            compound.putInt("Size", size);
            compound.putBoolean("Invulnerable", true);
            compound.putString("CustomName", Text.Serializer.toJson(new LiteralText("§bDownload Jex Client")));
            givePlayerStack(context, stack);
            return 1;
        }).then(argument("pos", Vec3ArgumentType.vec3()).executes(context -> {
            Vec3d vec = Vec3ArgumentType.getVec3(context, "pos");
            int size = IntegerArgumentType.getInteger(context, "size");
            ItemStack stack = new ItemStack(Items.SLIME_SPAWN_EGG);
            stack.setCustomName(new LiteralText("§7Slime size §b" + size));
            NbtCompound compound = stack.getOrCreateSubTag("EntityTag");
            compound.putBoolean("PersistenceRequired", true);
            compound.putString("id", "minecraft:slime");
            compound.putInt("Size", size);
            compound.putBoolean("Invulnerable", true);
            compound.putString("CustomName", Text.Serializer.toJson(new LiteralText("§bDownload Jex Client")));
            NbtList listTag = new NbtList();
            listTag.add(NbtDouble.of(vec.getX()));
            listTag.add(NbtDouble.of(vec.getY()));
            listTag.add(NbtDouble.of(vec.getZ()));
            compound.put("Pos", listTag);
            givePlayerStack(context, stack);
            return 1;
        })))).then(literal("firework").then(argument("explosions", IntegerArgumentType.integer(200)).executes(context -> {
            int explosions = IntegerArgumentType.getInteger(context, "explosions");
            ItemStack firework = new ItemStack(Items.FIREWORK_ROCKET);
            NbtCompound baseCompound = new NbtCompound();
            NbtCompound tagCompound = new NbtCompound();
            NbtList explosionList = new NbtList();

            for(int i = 0; i < explosions; i++)
            {
                NbtCompound explosionCompound = new NbtCompound();

                Random rand = new Random();
                explosionCompound.putByte("Type", (byte)rand.nextInt(5));

                int colors[] = {1973019,11743532,3887386,5320730,2437522,8073150,2651799,11250603,4408131,14188952,4312372,14602026,6719955,12801229,15435844,15790320};

                explosionCompound.putIntArray("Colors", colors);
                explosionList.add(explosionCompound);
            }
            tagCompound.putInt("Flight", 0);
            tagCompound.put("Explosions", explosionList);
            baseCompound.put("Fireworks", tagCompound);
            firework.setTag(baseCompound);
            givePlayerStack(context, firework);
            return 1;
        }))).then(literal("lightning").executes(context -> {
            ItemStack stack = new ItemStack(Items.ELDER_GUARDIAN_SPAWN_EGG);
            stack.setCustomName(new LiteralText("§bJex Lightning"));
            NbtCompound compound = stack.getOrCreateSubTag("EntityTag");
            compound.putString("id", "minecraft:lightning_bolt");
            givePlayerStack(context, stack);
            return 1;
        }).then(argument("pos", Vec3ArgumentType.vec3()).executes(context -> {
            Vec3d vec = Vec3ArgumentType.getVec3(context, "pos");
            ItemStack stack = new ItemStack(Items.ELDER_GUARDIAN_SPAWN_EGG);
            stack.setCustomName(new LiteralText("§bJex Lightning"));
            NbtCompound compound = stack.getOrCreateSubTag("EntityTag");
            compound.putString("id", "minecraft:lightning_bolt");
            NbtList listTag = new NbtList();
            listTag.add(NbtDouble.of(vec.getX()));
            listTag.add(NbtDouble.of(vec.getY()));
            listTag.add(NbtDouble.of(vec.getZ()));
            compound.put("Pos", listTag);
            givePlayerStack(context, stack);
            return 1;
        }))).then(literal("holo").then(argument("pos", Vec3ArgumentType.vec3()).then(argument("message", MessageArgumentType.message()).executes(context -> {
            if (!Wrapper.INSTANCE.getLocalPlayer().isCreative()) {
                ChatHelper.INSTANCE.addClientMessage("You must be in creative for this command!");
                return 0;
            }
            String message = MessageArgumentType.getMessage(context, "message").asString().replace("&", "\247");
            Vec3d vec = Vec3ArgumentType.getVec3(context, "pos");
            ItemStack stack = new ItemStack(Items.ARMOR_STAND);
            NbtCompound tag = new NbtCompound();
            NbtList listTag = new NbtList();
            listTag.add(NbtDouble.of(vec.getX()));
            listTag.add(NbtDouble.of(vec.getY()));
            listTag.add(NbtDouble.of(vec.getZ()));
            tag.putBoolean("Invisible", true);
            tag.putBoolean("Invulnerable", true);
            tag.putBoolean("Interpret", true);
            tag.putBoolean("NoGravity", true);
            tag.putBoolean("CustomNameVisible", true);
            tag.putString("CustomName", Text.Serializer.toJson(new LiteralText(message)));
            tag.put("Pos", listTag);
            stack.putSubTag("EntityTag", tag);
            givePlayerStack(context, stack);
            return 1;
        }))).then(argument("message", MessageArgumentType.message()).executes(context -> {
            String message = MessageArgumentType.getMessage(context, "message").asString().replace("&", "\247");

            ItemStack stack = new ItemStack(Items.ARMOR_STAND);
            NbtCompound tag = new NbtCompound();
            NbtList listTag = new NbtList();
            listTag.add(NbtDouble.of(Wrapper.INSTANCE.getLocalPlayer().getX()));
            listTag.add(NbtDouble.of(Wrapper.INSTANCE.getLocalPlayer().getY()));
            listTag.add(NbtDouble.of(Wrapper.INSTANCE.getLocalPlayer().getZ()));
            tag.putBoolean("Invisible", true);
            tag.putBoolean("Invulnerable", true);
            tag.putBoolean("Interpret", true);
            tag.putBoolean("NoGravity", true);
            tag.putBoolean("CustomNameVisible", true);
            tag.putString("CustomName", Text.Serializer.toJson(new LiteralText(message)));
            tag.put("Pos", listTag);
            stack.putSubTag("EntityTag", tag);
            givePlayerStack(context, stack);
            return 1;
        }))).then(literal("enderman").then(argument("block", BlockStateArgumentType.blockState()).executes(context -> {
            BlockState blockState = BlockStateArgumentType.getBlockState(context, "block").getBlockState();
            ItemStack stack = new ItemStack(Items.PARROT_SPAWN_EGG);
            stack.setCustomName(new LiteralText("§bJex Enderman"));
            NbtCompound compound = stack.getOrCreateSubTag("EntityTag");
            compound.putString("id", "minecraft:enderman");
            compound.put("carriedBlockState", NbtHelper.fromBlockState(blockState));
            givePlayerStack(context, stack);
            return 1;
        }))).then(literal("cmdbook").then(argument("title", StringArgumentType.string()).then(argument("author", PlayerNameArgumentType.playerName()).then(argument("text", StringArgumentType.string()).then(argument("command", MessageArgumentType.message()).executes(context -> {
            String title = StringArgumentType.getString(context, "title").replace("_", " ");
            String text = StringArgumentType.getString(context, "text").replace("_", " ");
            String cmd = MessageArgumentType.getMessage(context, "command").asString();
            String author = PlayerNameArgumentType.getPlayerName(context, "author");
            ItemStack itemStack = new ItemStack(Items.WRITTEN_BOOK);

            Text t = Texts.setStyleIfAbsent(new LiteralText(text + " ".repeat(1000)), Style.EMPTY.withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, cmd)));

            NbtList pages = new NbtList();
            JexClient.INSTANCE.getLogger().info(t);
            pages.add(NbtString.of(Text.Serializer.toJson(t)));
            pages.add(NbtString.of(Text.Serializer.toJson(new LiteralText(" "))));

            itemStack.putSubTag("pages", pages);
            itemStack.putSubTag("author", NbtString.of(author));
            itemStack.putSubTag("title", NbtString.of(title));
            givePlayerStack(context, itemStack);
            return 1;
        })))))).then(literal("dudtnt").executes(context -> {
            ItemStack stack = new ItemStack(Items.DROWNED_SPAWN_EGG);
            stack.setCustomName(new LiteralText("§cDUD TNT"));
            NbtCompound compound = stack.getOrCreateSubTag("EntityTag");
            compound.putString("id", "minecraft:tnt");
            compound.putInt("Fuse", 30000);
            compound.putBoolean("Invulnerable", true);
            givePlayerStack(context, stack);
            return 1;
        }).then(argument("pos", Vec3ArgumentType.vec3()).executes(context -> {
            Vec3d vec = Vec3ArgumentType.getVec3(context, "pos");
            ItemStack stack = new ItemStack(Items.DROWNED_SPAWN_EGG);
            stack.setCustomName(new LiteralText("§cDUD TNT"));
            NbtCompound compound = stack.getOrCreateSubTag("EntityTag");
            compound.putString("id", "minecraft:tnt");
            compound.putInt("Fuse", 30000);
            compound.putBoolean("Invulnerable", true);
            NbtList listTag = new NbtList();
            listTag.add(NbtDouble.of(vec.getX()));
            listTag.add(NbtDouble.of(vec.getY()));
            listTag.add(NbtDouble.of(vec.getZ()));
            compound.put("Pos", listTag);
            givePlayerStack(context, stack);
            return 1;
        }))).then(literal("commandblock").then(argument("command", MessageArgumentType.message()).executes(context -> {
            String command = MessageArgumentType.getMessage(context, "command").asString();
            ItemStack stack = new ItemStack(Items.BEE_SPAWN_EGG);
            stack.setCustomName(new LiteralText("§bJex Command Block"));
            NbtCompound entityCompound = stack.getOrCreateSubTag("EntityTag");
            entityCompound.putInt("Time", 1);
            entityCompound.putString("id", "minecraft:falling_block");
            NbtCompound compound = new NbtCompound();

            NbtCompound tileEntityData = new NbtCompound();
            tileEntityData.putString("Command", command);
            compound.putString("Name", "minecraft:command_block");
            entityCompound.put("BlockState", compound);
            entityCompound.put("TileEntityData", tileEntityData);
            givePlayerStack(context, stack);
            return 1;
        }))));
        dispatcher.register(literal("items").redirect(node));
    }

    private void givePlayerStack(CommandContext<FabricClientCommandSource> context, ItemStack itemStack) {
        if (!context.getSource().getPlayer().getAbilities().creativeMode) {
            ChatHelper.INSTANCE.addClientMessage("You must be in creative to use this command");
            return;
        }
        NetworkHelper.INSTANCE.sendPacket(new CreativeInventoryActionC2SPacket(36 + InventoryHelper.INSTANCE.getInventory().selectedSlot, itemStack));
    }

    @Override
    public int run(CommandContext<FabricClientCommandSource> context) throws CommandSyntaxException {
        return 0;
    }
}
